package com.aio.kgo.simple.form.database.mysql.service;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.IdUtil;
import com.aio.kgo.simple.form.common.domain.save.ModelDefinitionDo;
import com.aio.kgo.simple.form.common.enums.ModelStatusEnum;
import com.aio.kgo.simple.form.common.exceptions.ModelAlreadyExistException;
import com.aio.kgo.simple.form.common.exceptions.ModelNotFoundException;
import com.aio.kgo.simple.form.database.domain.params.QueryModelParams;
import com.aio.kgo.simple.form.database.mysql.domain.dao.ModelDo;
import com.aio.kgo.simple.form.database.mysql.mapper.AioModelMapper;
import com.aio.kgo.simple.form.database.service.AioModelService;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.kgo.flow.common.domain.page.KgoPage;
import com.kgo.flow.common.domain.page.PageResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author lizhenming
 * @desc:
 * @date 2023/12/26 22:41
 */
@Slf4j
@Service
public class MysqlModelService implements AioModelService {
    @Autowired
    private AioModelMapper aioModelMapper;

    @Override
    public ModelDefinitionDo createModel(ModelDefinitionDo definitionDo) {
        Assert.notNull(definitionDo,"参数不能为空");
        Assert.notNull(definitionDo.getModelKey(),"模型标识不能为空");
        Assert.notNull(definitionDo.getModule(),"功能模块不能为空");
        Assert.notNull(definitionDo.getModelDesign(),"模型定义不能为空");
        ModelDefinitionDo modelByKeyAndModule = getModelByKeyAndModule(definitionDo.getModelKey(), definitionDo.getModule());
        if (ObjectUtils.isNotEmpty(modelByKeyAndModule)){
            log.warn("新增模型定义 - 模型标识[ {} ] 模块[ {} ] 的模型定义已存在。",definitionDo.getModelKey(), definitionDo.getModule());
            throw new ModelAlreadyExistException();
        }

        ModelDo modelDo = Convert.convert(ModelDo.class,definitionDo);
        if (StringUtils.isBlank(modelDo.getId())){
            modelDo.setId(IdUtil.getSnowflakeNextIdStr());
        }
        modelDo.setCreateTime(new Date());
        modelDo.setUpdateTime(new Date());
        modelDo.setModelStatus(ModelStatusEnum.ENABLE.getStatus());
        modelDo.setModelDefinition(JSON.toJSONString(definitionDo.getModelDesign()));
        int insert = aioModelMapper.insert(modelDo);
        if (insert<1){
            log.warn("新增模型定义 - 新增失败，创建参数： {} ", JSON.toJSONString(definitionDo));
            return null;
        }
        return definitionDo;
    }

    @Override
    public ModelDefinitionDo updateModel(ModelDefinitionDo params) {
        Assert.notNull(params,"参数不能为空");
        Assert.notNull(params.getId(),"模型ID不能为空");

        // 根据模型定义ID获取模型定义
        ModelDefinitionDo modelDefinition = getModelById(params.getId());
        if (ObjectUtils.isEmpty(modelDefinition)){
            log.warn("更新模型定义 - 根据模型ID[ {} ] 未能获取到模型定义。",params.getId());
            throw new ModelNotFoundException();
        }

        ModelDo updateModel = new ModelDo();
        updateModel.setId(params.getId());

        // 如果参数 既有模型KEY 又有模型所属模块，就需要判断这个定义和功能模块是否已存在
        if (StringUtils.isNoneBlank(params.getModelKey(),params.getModule())){
            ModelDefinitionDo modelByKeyAndModule = getModelByKeyAndModule(params.getModelKey(), params.getModule());

            // 如果模型不是空，并且模型不是当前需要更新的模型
            if (ObjectUtils.isNotEmpty(modelByKeyAndModule) && !(StringUtils.equals(modelByKeyAndModule.getId(),modelDefinition.getId()))){
                log.warn("更新模型定义 - 模型标识[ {} ] 模块[ {} ] 的模型定义已存在。",params.getModelKey(), params.getModule());
                throw new ModelAlreadyExistException();
            }

            updateModel.setModelKey(params.getModelKey());
            updateModel.setModule(params.getModule());
        }
        // 如果模型定义不是空并且与当前模型的Key不相同
        else if (StringUtils.isNotBlank(params.getModelKey())
                && (!StringUtils.equals(params.getModelKey(),modelDefinition.getModelKey()))){

            ModelDefinitionDo modelByKeyAndModule = getModelByKeyAndModule(params.getModelKey(), modelDefinition.getModule());
            // 如果模型不是空，并且模型不是当前需要更新的模型
            if (ObjectUtils.isNotEmpty(modelByKeyAndModule) && StringUtils.equals(modelByKeyAndModule.getId(),modelDefinition.getId())){
                log.warn("更新模型定义 - 模型标识[ {} ] 模块[ {} ] 的模型定义已存在。",params.getModelKey(), modelDefinition.getModule());
                throw new ModelAlreadyExistException();
            }
            updateModel.setModelKey(params.getModelKey());

        }
        // 如果模型模块不是空 ，并且模型模块不是当前模型定义的模块
        else if (StringUtils.isNotBlank(params.getModule())
                && (!StringUtils.equals(params.getModule(),modelDefinition.getModule()))){
            ModelDefinitionDo modelByKeyAndModule = getModelByKeyAndModule(params.getModelKey(), modelDefinition.getModule());
            // 如果模型不是空，并且模型不是当前需要更新的模型
            if (ObjectUtils.isNotEmpty(modelByKeyAndModule) && StringUtils.equals(modelByKeyAndModule.getId(),modelDefinition.getId())){
                log.warn("更新模型定义 - 模型标识[ {} ] 模块[ {} ] 的模型定义已存在。",params.getModelKey(), modelDefinition.getModule());
                throw new ModelAlreadyExistException();
            }
            updateModel.setModule(params.getModule());

        }

        if (ObjectUtils.isNotEmpty(params.getModelDesign())){
            updateModel.setModelDefinition(JSON.toJSONString(params.getModelDesign()));
        }

        if (ObjectUtils.isNotEmpty(params.getModelStatus())){
            updateModel.setModelStatus(params.getModelStatus());
        }

        if (StringUtils.isNotBlank(params.getRemark())) {
            updateModel.setRemark(params.getRemark());
        }

        updateModel.setUpdateTime(new Date());

        int updateResult = aioModelMapper.updateById(updateModel);
        log.info("更新模型定义 - 更新模型结果 : [ {} ] ,更新结果 ： {} ",updateResult,JSON.toJSONString(updateModel));
        return params;
    }

    @Override
    public ModelDefinitionDo getModelByKeyAndModule(String modelKey, String module) {
        LambdaQueryWrapper<ModelDo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ModelDo::getModelKey,modelKey);
        queryWrapper.eq(ModelDo::getModule,module);
        List<ModelDo> modelDos = aioModelMapper.selectList(queryWrapper);
        if (ObjectUtils.isEmpty(modelDos)){
            return null;
        }
        ModelDefinitionDo modelDefinition = modelDos.get(0).getModelDef();
        return modelDefinition;
    }

    @Override
    public ModelDefinitionDo getModelById(String modelId) {
        ModelDo modelDo = aioModelMapper.selectById(modelId);
        if (ObjectUtils.isEmpty(modelDo)){
            return null;
        }
        return modelDo.getModelDef();
    }

    @Override
    public ModelDefinitionDo enableModel(String modelId) {
        ModelDefinitionDo modelDefinition = getModelById(modelId);
        if (ObjectUtils.isEmpty(modelDefinition)){
            log.warn("弃用模型定义 - 根据模型ID[ {} ]未获取到模型定义 。 ",modelId);
            throw new ModelNotFoundException();
        }
        ModelDo updateModel = new ModelDo();
        updateModel.setId(modelId);
        updateModel.setUpdateTime(new Date());
        updateModel.setModelStatus(ModelStatusEnum.ENABLE.getStatus());
        int i = aioModelMapper.updateById(updateModel);
        modelDefinition.setModelStatus(ModelStatusEnum.ENABLE.getStatus());
        return modelDefinition;
    }

    @Override
    public ModelDefinitionDo disableModel(String modelId) {
        ModelDefinitionDo modelDefinition = getModelById(modelId);
        if (ObjectUtils.isEmpty(modelDefinition)){
            log.warn("弃用模型定义 - 根据模型ID[ {} ]未获取到模型定义 。 ",modelId);
            throw new ModelNotFoundException();
        }
        ModelDo updateModel = new ModelDo();
        updateModel.setId(modelId);
        updateModel.setUpdateTime(new Date());
        updateModel.setModelStatus(ModelStatusEnum.DISABLE.getStatus());
        int i = aioModelMapper.updateById(updateModel);
        modelDefinition.setModelStatus(ModelStatusEnum.DISABLE.getStatus());
        return modelDefinition;
    }

    private LambdaQueryWrapper<ModelDo> queryWrapper(QueryModelParams params){
        LambdaQueryWrapper<ModelDo> queryWrapper = new LambdaQueryWrapper<>();

        queryWrapper.select(ModelDo::getId,ModelDo::getModelStatus,ModelDo::getModelName
                ,ModelDo::getModelKey,ModelDo::getModule,ModelDo::getCreateTime,ModelDo::getUpdateTime);

        if (StringUtils.isNotBlank(params.getModelKey())){
            queryWrapper.eq(ModelDo::getModelKey,params.getModelKey());
        }
        if (StringUtils.isNotBlank(params.getModelName())){
            queryWrapper.like(ModelDo::getModelName,params.getModelName());
        }
        if (StringUtils.isNotBlank(params.getModule())){
            queryWrapper.eq(ModelDo::getModule,params.getModule());
        }
        return queryWrapper;
    }
    @Override
    public List<ModelDefinitionDo> getModelList(QueryModelParams params) {
        KgoPage page = new KgoPage();
        page.setPageSize(1000);
        PageResult<ModelDefinitionDo> modelPage = getModelPage(params, page);
        return modelPage.getList();
    }

    @Override
    public PageResult<ModelDefinitionDo> getModelPage(QueryModelParams params, KgoPage page) {

        IPage<ModelDo> pagePlus = new Page<>(page.getPageNum(),page.getPageSize());
        LambdaQueryWrapper<ModelDo> queryWrapper = queryWrapper(params);
        IPage<ModelDo> modelDoIPage = aioModelMapper.selectPage(pagePlus, queryWrapper);

        PageResult<ModelDefinitionDo> result = new PageResult();
        result.setTotal((int) modelDoIPage.getTotal());

        List<ModelDefinitionDo> definitionDoList = new ArrayList<>();
        for (ModelDo record : modelDoIPage.getRecords()) {
            definitionDoList.add(record.getModelDef());
        }
        result.setList(definitionDoList);
        return result;
    }


}
